using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using UnityEngine;
using LS.UnityExtensions;
using NUnit.Framework;

namespace LS.Digitize
{
    public class DictionarySerializer: KeyValuePairCollectionSerializer
    {
        public DictionarySerializer(Type type) : base(type)
        {
            var types = LSReflection.GetElementTypes(type);
            subTypes = types;
        }
        
        public DictionarySerializer(Type type, Type keyType, Type valueType) : base(type, keyType, valueType)
        {
            
        }

        public override void Write(IWriter writer, object obj)
        {
            var keySerializer = KeySerializer;
            var valueSerializer = ValueSerializer;
            var dict = (IDictionary)obj;
            using (writer.WriteDictionaryScope())
            {
                int i=0;
                foreach(DictionaryEntry kvp in dict)
                {
                    using (writer.WriteDictionaryKeyScope(i))
                        keySerializer.Write(writer,kvp.Key);
                    
                    using (writer.WriteDictionaryValueScope(i))
                        valueSerializer.Write(writer,kvp.Key);
                    i++;
                }
            }
        }

        public override object Read(IReader reader)
        {
            if(reader.StartReadDictionary())
                return null;

            List<KeyValuePair<object, object>> list = new List<KeyValuePair<object, object>>();
            if (!ReadCollection(reader, list, this.KeySerializer, ValueSerializer, out bool nullCollection))
            {
                if(nullCollection)
                    return null;
                return LSReflection.CreateInstance(DataType);
            }
            
            var dict = (IDictionary)LSReflection.CreateInstance(DataType);
            foreach (var kvp in list)
            {
                dict.Add(kvp.Key, kvp.Value);
            }
            reader.EndReadDictionary();
            return dict;
        }
    }
    
    public class DictionarySerializer<TKey, TValue>: KeyValuePairCollectionSerializer<Dictionary<TKey,TValue>,TKey,TValue>
    {
        public DictionarySerializer(Type type) : base(type)
        {
            var types = LSReflection.GetElementTypes(type);
            subTypes = types;
        }
        
        public DictionarySerializer(Type type, Type keyType, Type valueType) : base(type, keyType, valueType)
        {
            
        }

        public override void Write(IWriter writer, object obj)
        {
            WriteData(writer, (Dictionary<TKey, TValue>)obj);
        }

        public override object Read(IReader reader)
        {
            return ReadData(reader);
        }
        
        public override void WriteData(IWriter writer, Dictionary<TKey, TValue> obj)
        {
            var keySerializer = KeySerializer;
            var valueSerializer = ValueSerializer;
            var dict = obj;
            using (writer.WriteDictionaryScope())
            {
                int i=0;
                foreach(KeyValuePair<TKey,TValue> kvp in dict)
                {
                    using (writer.WriteDictionaryKeyScope(i))
                        keySerializer.Write(writer,kvp.Key);
                    
                    using (writer.WriteDictionaryValueScope(i))
                        valueSerializer.Write(writer,kvp.Key);
                    i++;
                }
            }
        }

        public override Dictionary<TKey, TValue> ReadData(IReader reader)
        {
            if(reader.StartReadDictionary())
                return null;

            List<KeyValuePair<TKey, TValue>> collection = new List<KeyValuePair<TKey, TValue>>();
            if (!ReadCollection(reader, collection, this.KeySerializer, ValueSerializer, out bool nullCollection))
            {
                if(nullCollection)
                    return null;
                return new Dictionary<TKey, TValue>();
            }
            
            var dict = new Dictionary<TKey, TValue>();
            foreach (var kvp in collection)
            {
                dict.Add(kvp.Key, kvp.Value);
            }
            reader.EndReadDictionary();

            return dict;
        }
        
        public virtual void ReadInto(IReader reader, ref Dictionary<TKey, TValue> obj)
        {
            throw new NotImplementedException();
        }
    }
}